package br.com.dubs.persistence.dao;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import br.com.dubs.persistence.exceptions.GenericDAOException;

public abstract class GenericDAO<T extends Serializable> {

	@PersistenceContext(unitName = "com.dubs")
	protected EntityManager em;
	// protected EntityTransaction et;
	public static final int SAVE = 1;
	public static final int DELETE = 2;
	public static final int UPDATE = 3;

	// protected static Logger log = Logger.getLogger(GenericDAO.class);
	/**
	 * Loads an entity using the given Id
	 * 
	 * @param elmnt
	 *            An object of the entity that you are looking for.
	 * @param id
	 *            of the entity that you are looking for.
	 * @return The entity or null if is not found.
	 */
	@SuppressWarnings("unchecked")
	public T load(T elmnt, Integer id) {
		// log.debug("TESTE");
		return (T) em.find(elmnt.getClass(), id);
	}

	/**
	 * 
	 * @param pageSize
	 *            if greater than 0 will set the pageSize to the giver value. If
	 *            equals 0 will return all objects that it finds
	 * @param maxResults
	 *            if greater than 0 set the pageStart to the giver value. If
	 *            equals 0 will return all objects that it finds
	 * @return Return the list of all objects of the given class.
	 * @throws JsonDataProviderException
	 */
	@SuppressWarnings("unchecked")
	public List<T> listAll(Class<? extends Serializable> c, int pageSize,
			int pageStart) throws GenericDAOException {
		Query query = null;
		List<T> reply = null;
		try {
			query = em.createQuery("SELECT c FROM " + c.getSimpleName()
					+ " AS c");

			if (pageSize > 0 && pageStart > 0) {
				query.setFirstResult(pageStart);
				query.setMaxResults(pageSize);
			}
			reply = query.getResultList();
		} catch (Exception e) {
			throw new GenericDAOException("Object List Failure", e);
		}

		if (reply.isEmpty()) {
			return null;
		} else {
			return reply;
		}
	}

	/**
	 * 
	 * @param elmnt
	 *            The element that should be persisted
	 * @return Null if the element is persisted successfully
	 * @throws GenericDAOException
	 * @throws JsonDataProviderException
	 */
	public T add(T elmnt) throws GenericDAOException {
		return process(elmnt, SAVE);
	}

	/**
	 * 
	 * @param elmnt
	 *            The element that should be remove.
	 * @return Null if the element is remvoed successfully
	 * @throws GenericDAOException
	 */
	public T del(T elmnt, Long id) throws GenericDAOException {

		return process((T) em.getReference(elmnt.getClass(), id), DELETE);
	}

	/**
	 * 
	 * @param elmnt
	 *            The element that should be updated.
	 * @return Null if the element is updated sucessfully.
	 * @throws GenericDAOException
	 * @throws JsonDataProviderException
	 */
	public T update(T elmnt) throws GenericDAOException {
		return process(elmnt, UPDATE);
	}

	public T process(T elmnt, int type) throws GenericDAOException {
		// log.debug(">process()");
		try {
			if (em == null) {
				throw new PersistenceException("Persistence Unit Not Found");
			}
			// TODO Implement Transaction Control
			// et = em.getTransaction();
			// et.begin();
			switch (type) {
			case SAVE:
				// log.debug("SAVE");
				// em.merge(elmnt);
				em.persist(elmnt);
				break;
			case DELETE:

				em.remove(elmnt);
				break;
			case UPDATE:
				// log.debug("UPDATE");
				em.merge(elmnt);
				break;
			default:
				throw new GenericDAOException("Invalid Operation");
			}

		} catch (PersistenceException e) {
			throw new GenericDAOException(e.getMessage(), e);
		} catch (Exception e) {
			throw new GenericDAOException("Unkown Error!", e);
		}

		/*
		 * finally { if (et.isActive()) { et.rollback(); } //
		 * log.debug("<process()"); }
		 */
		return null;
	}

}
